/*
 * sem_thread.cxx
 * 
 * Copyright 2022 redmi <redmi@DESKTOP-G0MT3E0>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 * 
 * 
 */
#define LOG_TAG "thread"
#include <iostream>
#include <chrono>
#include <thread>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#include<stdio.h>
#include "../utils/log.h"
#include "../video_test/video_algo_sim.h"
using  namespace  std;
#define WORK_THREAD_NUM 2
#define WORK_BUFFER_SIZE 2
bool work_thread_running;
bool main_thread_running;
static int index;
sem_t  main_sem;
sem_t first_thread_sem;
sem_t second_thread_sem;
char* work_buffers[WORK_THREAD_NUM];
thread* main_thread;
thread* first_thread;
thread* second_thread ;

void MainThreadProcess() {
    while (main_thread_running) {
        TRACE_B("id:%d", index);
		LOGI("AsyncFramework::MainThreadProcess :E\n");
        memset(work_buffers[index % WORK_THREAD_NUM], 0, WORK_BUFFER_SIZE);
        sprintf(work_buffers[index % WORK_THREAD_NUM], "FrameIndex=%d ", index);
        //通知第一个工作线程处理
        sem_post(&first_thread_sem);
        if (index == 0) {
            //第 0 帧直接返回，不交给工作线程处理
            LOGI("AsyncFramework::MainThreadProcess %s\n", work_buffers[index % WORK_THREAD_NUM]);
            index++;
            continue;
        } else {
            //等待第二个工作线程的处理结果 
            sem_wait(&main_sem);
        }
        LOGI("AsyncFramework::MainThreadProcess %s\n", work_buffers[(index - 1) % WORK_THREAD_NUM]);
        index++;
        if (index == 5) break;//生成20帧
    }
    LOGI("AsyncFramework::MainThreadProcess end\n");
 
}

void FirstStepProcess() {
    LOGI("AsyncFramework::FirstStepProcess start\n");
    int index = 0;
    while (true) {
        //等待主线程发来的信号
        TRACE_B("id:%d", index);
        sem_wait(&first_thread_sem);
        if(!work_thread_running) break;
        LOGI("AsyncFramework::FirstStepProcess index=%d\n", index);
        strcat(work_buffers[index % WORK_THREAD_NUM], "FirstStep ");
        //休眠模拟处理耗时
        //this_thread::sleep_for(chrono::milliseconds(200));
        SlimbeautyProcessSim();
        //处理完成后通知第二个工作线程进行第二步处理
        sem_post(&second_thread_sem);
        index++;
    }
    LOGI("AsyncFramework::FirstStepProcess end\n");
 
}
 
void SecondStepProcess() {
    LOGI("AsyncFramework::SecondStepProcess start\n");
    int index = 0;
    while (true) {
        //等待第一个工作线程发来的信号
        TRACE_B("id:%d", index);
        sem_wait(&second_thread_sem);
        if(!work_thread_running) break;
        LOGI("AsyncFramework::SecondStepProces index=%d\n", index);
        strcat(work_buffers[index % WORK_THREAD_NUM], "SecondStep");
        //休眠模拟处理耗时
        //this_thread::sleep_for(chrono::milliseconds(200));
        FacebeautyProcessSim();
        //第二步处理完成后通知主线程结束等待
        sem_post(&main_sem);
        index++;
    }
    LOGI("AsyncFramework::SecondStepProcess end\n");
}

class AsyncFramework{
public:
AsyncFramework() {
    memset(work_buffers, 0, sizeof(work_buffers));
	work_thread_running = true;
    main_thread_running = true;
 
     index = 0;
    // 初始化 3 个信号量
    sem_init(&main_sem, 0, 0);
    sem_init(&first_thread_sem, 0, 0);
    sem_init(&second_thread_sem, 0, 0);
 
    // WORK_THREAD_NUM = 2 ，为 2 个工作线程申请 2 块 buffer
    for (int i = 0; i < WORK_THREAD_NUM; ++i) {
        work_buffers[i] = static_cast<char *>(malloc(WORK_BUFFER_SIZE));
    }
    // 启动三个线程
     main_thread = new thread(MainThreadProcess);
     first_thread = new thread(FirstStepProcess);
     second_thread = new thread(SecondStepProcess);
 
}
// 析构函数
~AsyncFramework() {
    main_thread_running = false;
    main_thread->join();
    delete main_thread;
    main_thread = nullptr;
 
    work_thread_running = false;
    sem_post(&first_thread_sem);
    sem_post(&second_thread_sem);
    first_thread->join();
    second_thread->join();
 
    delete first_thread;
    first_thread = nullptr;
    delete second_thread;
    second_thread = nullptr;
 
    //销毁信号量
    sem_destroy(&main_sem);
    sem_destroy(&first_thread_sem);
    sem_destroy(&second_thread_sem);
 
    //释放缓冲区
    for (int i = 0; i < WORK_THREAD_NUM; ++i) {
        if (work_buffers[i]!=nullptr) {
            free(work_buffers[i]);
            work_buffers[i] = nullptr;
        }
    }
 
}	
};

int main()
{
    LOGI("main start E\n");
	AsyncFramework test;
	sleep(100);
	return 0;
}

